package org.hiro.actions;

import com.intellij.codeInsight.generation.PsiElementClassMember;
import com.intellij.ide.util.MemberChooser;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.ScrollType;
import com.intellij.openapi.editor.VisualPosition;
import com.intellij.openapi.editor.actionSystem.EditorWriteActionHandler;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElementFactory;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.codeStyle.CodeStyleManager;
import static org.hiro.GenerateBuilderContext.getConfiguration;
import static org.hiro.psi.PsiClassHelper.getAllAccessibleFieldsInHierarchyToDisplay;
import org.hiro.psi.PsiHelper;

import javax.swing.*;

class GenerateWithMethodActionHandler extends EditorWriteActionHandler {
    private PsiHelper psiHelper;
    private Editor editor;

    @Override
    public void executeWriteAction(Editor editor, DataContext dataContext) {
        this.editor = editor;
        psiHelper = new PsiHelper(dataContext);

        if (psiHelper.getCurrentElement() != null) {
            displayFieldSelectionDialog();
        }
    }

    private void displayFieldSelectionDialog() {
        final Project project = psiHelper.getProject();
        final PsiClass currentClass = psiHelper.getCurrentClass();
        final PsiElementFactory elementFactory = psiHelper.getElementFactory();
        final CodeStyleManager codeStyleManager = psiHelper.getCodeStyleManager();

        PsiElementClassMember[] fieldsToDisplay = getAllAccessibleFieldsInHierarchyToDisplay(currentClass);

        final MemberChooser<PsiElementClassMember> dialog = new MemberChooser<PsiElementClassMember>(fieldsToDisplay, false, true, project, false);
        dialog.setCopyJavadocVisible(false);
        dialog.selectElements(fieldsToDisplay);
        dialog.setTitle("Select fields to generate with methods for");

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                dialog.show();
                if (MemberChooser.CANCEL_EXIT_CODE == dialog.getExitCode()) {
                    return;
                }

                GenerateWithMethodWriter withMethodWriter = new GenerateWithMethodWriter(project, currentClass, elementFactory, codeStyleManager, dialog.getSelectedElements());
                CommandProcessor.getInstance().executeCommand(project, withMethodWriter, "Build with methods", null);

                if (getConfiguration().isMoveCursorToFirstMethod()) {
                    jumpToFirstMethod(currentClass, withMethodWriter.getFirstMethodName());
                }
            }
        });
    }

    private void jumpToFirstMethod(PsiClass currentClass, String methodName) {
        PsiMethod newMethod = psiHelper.findMethodByName(currentClass, methodName);
        if (newMethod != null) {
            int offset = newMethod.getTextOffset();
            if (offset > 2) {
                VisualPosition virtualPosition = editor.offsetToVisualPosition(offset);
                editor.getCaretModel().moveToVisualPosition(virtualPosition);
                editor.getScrollingModel().scrollToCaret(ScrollType.CENTER_DOWN);
            }
        }
    }
}
